package com.cloud.adrian.novel.book.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cloud.adrian.novel.book.dao.entity.BookChapter;
import com.cloud.adrian.novel.book.dao.entity.BookComment;
import com.cloud.adrian.novel.book.dao.entity.BookContent;
import com.cloud.adrian.novel.book.dao.entity.BookInfo;
import com.cloud.adrian.novel.book.dao.mapper.BookChapterMapper;
import com.cloud.adrian.novel.book.dao.mapper.BookCommentMapper;
import com.cloud.adrian.novel.book.dao.mapper.BookContentMapper;
import com.cloud.adrian.novel.book.dao.mapper.BookInfoMapper;
import com.cloud.adrian.novel.book.dto.req.*;
import com.cloud.adrian.novel.book.dto.resp.*;
import com.cloud.adrian.novel.book.manager.cache.*;
import com.cloud.adrian.novel.book.manager.feign.UserFeignManager;
import com.cloud.adrian.novel.book.service.BookService;
import com.cloud.adrian.novel.common.auth.UserHolder;
import com.cloud.adrian.novel.common.constant.AmqpConstants;
import com.cloud.adrian.novel.common.constant.DatabaseConstants;
import com.cloud.adrian.novel.common.constant.ErrorCodeEnum;
import com.cloud.adrian.novel.common.resp.PageRespDto;
import com.cloud.adrian.novel.common.resp.RestResp;
import com.cloud.adrian.novel.config.annotation.Key;
import com.cloud.adrian.novel.config.annotation.Lock;
import com.cloud.adrian.novel.config.exception.BusinessException;
import com.cloud.adrian.novel.user.dto.resp.UserInfoRespDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 小说模块 服务实现类
 * @Author: xiangguiliang
 * @version: 1.0
 * @since: 2024/05/18
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class BookServiceImpl implements BookService {

    private final BookRankCacheManager bookRankCacheManager;
    private final BookCategoryCacheManager bookCategoryCacheManager;
    private final BookCommentMapper bookCommentMapper;
    private final UserFeignManager userFeignManager;
    private final BookInfoMapper bookInfoMapper;
    private final BookInfoCacheManager bookInfoCacheManager;
    private final BookChapterCacheManager bookChapterCacheManager;
    private final BookContentCacheManager bookContentCacheManager;
    private final BookChapterMapper bookChapterMapper;
    private final BookContentMapper bookContentMapper;
    private static final Integer REC_BOOK_COUNT = 4;
    private final RabbitTemplate rabbitTemplate;

    @Override
    public RestResp<List<BookInfoRespDto>> listBookInfoByIds(List<Long> bookIds) {
        QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.in(DatabaseConstants.CommonColumnEnum.ID.getName(), bookIds);
        return RestResp.ok(
                bookInfoMapper.selectList(queryWrapper).stream().map(v -> BookInfoRespDto.builder()
                        .id(v.getId())
                        .bookName(v.getBookName())
                        .authorName(v.getAuthorName())
                        .picUrl(v.getPicUrl())
                        .bookDesc(v.getBookDesc())
                        .build()).toList()
        );
    }

    @Override
    public RestResp<List<BookRankRespDto>> listVisitRankBooks() {
        return RestResp.ok(bookRankCacheManager.listVisitRankBooks());
    }

    @Override
    public RestResp<List<BookRankRespDto>> listNewestRankBooks() {
        return RestResp.ok(bookRankCacheManager.listNewestRankBooks());
    }

    @Override
    public RestResp<List<BookRankRespDto>> listUpdateRankBooks() {
        return RestResp.ok(bookRankCacheManager.listUpdateRankBooks());
    }

    @Override
    public RestResp<BookInfoRespDto> getBookById(Long bookId) {
        return RestResp.ok(bookInfoCacheManager.getBookInfo(bookId));
    }

    @Override
    public RestResp<Void> addVisitCount(Long bookId) {
        bookInfoMapper.addVisitCount(bookId);
        return RestResp.ok();
    }

    @Override
    public RestResp<BookChapterAboutRespDto> getLastChapterAbout(Long bookId) {
        // 查询小说信息
        BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(bookId);
        // 查询最新章节信息
        BookChapterRespDto lastChapter = bookChapterCacheManager.getChapter(bookInfo.getLastChapterId());
        // 查询章节内容
        String bookContent = bookContentCacheManager.getBookContent(lastChapter.getId());
        // 查询章节总数
        QueryWrapper<BookChapter> chapterQueryWrapper = new QueryWrapper<>();
        chapterQueryWrapper.eq(DatabaseConstants.BookChapterTable.COLUMN_BOOK_ID, bookId);
        Long chapterCount = bookChapterMapper.selectCount(chapterQueryWrapper);
        // 返回结果
        return RestResp.ok(BookChapterAboutRespDto.builder()
                        .chapterInfo(lastChapter)
                        .chapterTotal(chapterCount)
                        .contentSummary("".equals(bookContent) ? "" :bookContent.substring(0,40))
                        .build());
    }

    @Override
    public RestResp<BookCommentRespDto> listNewestComments(Long bookId) {
        // 查询评论总量
        QueryWrapper<BookComment> commentCountQueryWrapper = new QueryWrapper<>();
        commentCountQueryWrapper.eq(DatabaseConstants.BookCommentTable.COLUMN_BOOK_ID, bookId);
        Long commentTotal = bookCommentMapper.selectCount(commentCountQueryWrapper);
        BookCommentRespDto bookCommentRespDto = BookCommentRespDto.builder()
                .commentTotal(commentTotal).build();
        if (commentTotal > 0) {
            // 查询最新的评论列表
            QueryWrapper<BookComment> commentQueryWrapper = new QueryWrapper<>();
            commentQueryWrapper.eq(DatabaseConstants.BookCommentTable.COLUMN_BOOK_ID, bookId)
                    .orderByDesc(DatabaseConstants.CommonColumnEnum.CREATE_TIME.getName())
                    .last(DatabaseConstants.SqlEnum.LIMIT_5.getSql());
            List<BookComment> bookComments = bookCommentMapper.selectList(commentQueryWrapper);

            // 通过评论查询用户信息
            List<Long> userIds = bookComments.stream().map(BookComment::getUserId).toList();
            List<UserInfoRespDto> userInfos = userFeignManager.listUserInfoByIds(userIds);
            Map<Long, UserInfoRespDto> userInfoMap = userInfos.stream()
                    .collect(Collectors.toMap(UserInfoRespDto::getId, Function.identity()));

            // 封装评论列表
            List<BookCommentRespDto.CommentInfo> commentInfos = bookComments.stream().map(v -> BookCommentRespDto.CommentInfo.builder()
                    .id(v.getId())
                    .commentUserId(
                            userInfoMap.get(v.getUserId()).getId())
                    .commentContent(v.getCommentContent())
                    .commentUser(userInfoMap.get(v.getUserId()).getUsername())
                    .commentUserPhoto(userInfoMap.get(v.getUserId()).getUserPhoto())
                    .commentTime(v.getCreateTime()).build()).toList();
            bookCommentRespDto.setComments(commentInfos);
        } else {
            bookCommentRespDto.setComments(Collections.emptyList());
        }
        return RestResp.ok(bookCommentRespDto);
    }

    @Override
    public RestResp<List<BookInfoRespDto>> listRecBooks(Long bookId) throws NoSuchAlgorithmException {
//        Long categoryId = bookInfoCacheManager.getBookInfo(bookId).getCategoryId();
//        List<Long> lastUpdateIdList = bookInfoCacheManager.getLastUpdateIdList(categoryId);
//        List<BookInfoRespDto> respDtoList = new ArrayList<>();
//        List<Integer> recIdIndexList = new ArrayList<>();
//        int count = 0;
//        Random rand = SecureRandom.getInstanceStrong();
//        while (count < REC_BOOK_COUNT) {
//            int recIdIndex = rand.nextInt(lastUpdateIdList.size());
//            if (!recIdIndexList.contains(recIdIndex)) {
//                recIdIndexList.add(recIdIndex);
//                bookId = lastUpdateIdList.get(recIdIndex);
//                BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(bookId);
//                respDtoList.add(bookInfo);
//                count++;
//            }
//        }
        Long categoryId = bookInfoCacheManager.getBookInfo(bookId).getCategoryId();
        List<Long> lastUpdateIdList = new ArrayList<>(bookInfoCacheManager.getLastUpdateIdList(categoryId));
        List<BookInfoRespDto> respDtoList = new ArrayList<>();
        Collections.shuffle(lastUpdateIdList, new Random());
        for (int i = 0; i < REC_BOOK_COUNT && i < lastUpdateIdList.size(); i++) {
            Long recBookId = lastUpdateIdList.get(i);
            BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(recBookId);
            respDtoList.add(bookInfo);
        }
        return RestResp.ok(respDtoList);
    }

    @Lock(prefix = "userComment")
    @Override
    public RestResp<Void> saveComment(
            @Key(expr = "#{userId + '::' + bookId") BookCommentReqDto dto) {
        // 校验用户是否已经发评论了（目前是防止重复刷，后期优化）
        QueryWrapper<BookComment> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookCommentTable.COLUMN_USER_ID, dto.getUserId())
                .eq(DatabaseConstants.BookCommentTable.COLUMN_BOOK_ID, dto.getBookId());
        if (bookCommentMapper.selectCount(queryWrapper) > 0) {
            // 用户已经评论过
            return RestResp.fail(ErrorCodeEnum.USER_COMMENTED);
        }
        BookComment bookComment = new BookComment();
        bookComment.setBookId(dto.getBookId());
        bookComment.setUserId(dto.getUserId());
        bookComment.setCommentContent(dto.getCommentContent());
        bookComment.setCreateTime(LocalDateTime.now());
        bookCommentMapper.insert(bookComment);
        return RestResp.ok();
    }

    @Override
    public RestResp<Void> updateComment(BookCommentReqDto dto) {
        QueryWrapper<BookComment> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.CommonColumnEnum.ID.getName(), dto.getCommentId())
                .eq(DatabaseConstants.BookCommentTable.COLUMN_USER_ID, dto.getUserId());
        BookComment bookComment = new BookComment();
        bookComment.setCommentContent(dto.getCommentContent());
        bookComment.setUpdateTime(LocalDateTime.now());
        bookCommentMapper.update(bookComment, queryWrapper);
        return RestResp.ok();
    }

    @Override
    public RestResp<Void> deleteComment(BookCommentReqDto dto) {
        QueryWrapper<BookComment> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.CommonColumnEnum.ID.getName(), dto.getCommentId())
                .eq(DatabaseConstants.BookCommentTable.COLUMN_USER_ID, dto.getUserId());
        bookCommentMapper.delete(queryWrapper);
        return RestResp.ok();
    }

    @Override
    public RestResp<List<BookChapterRespDto>> listChapters(Long bookId) {
        QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookChapterTable.COLUMN_BOOK_ID, bookId)
                .orderByAsc(DatabaseConstants.BookChapterTable.COLUMN_CHAPTER_NUM);
        return RestResp.ok(bookChapterMapper.selectList(queryWrapper).stream().map(
                v -> BookChapterRespDto.builder()
                        .id(v.getId())
                        .chapterName(v.getChapterName())
                        .isVip(v.getIsVip()).build()
        ).toList());
    }

    @Override
    public RestResp<BookContentAboutRestDto> getBookContentAbout(Long chapterId) {
        log.debug("userId:{}", UserHolder.getUserId());
        // 查询章节内容
        BookChapterRespDto bookChapter = bookChapterCacheManager.getChapter(chapterId);
        // 查询章节小说内容
        String bookContent = bookContentCacheManager.getBookContent(chapterId);
        // 查询小说信息
        BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(bookChapter.getBookId());
        // 组装数据并返回
        return RestResp.ok(BookContentAboutRestDto.builder()
                        .bookInfo(bookInfo)
                        .chapterInfo(bookChapter)
                        .bookContent(bookContent)
                        .build());
    }

    @Override
    public RestResp<Long> getPreChapterId(Long chapterId) {
        BookChapterRespDto chapter = bookChapterCacheManager.getChapter(chapterId);
        Long bookId = chapter.getBookId();
        Integer chapterNum = chapter.getChapterNum();
        // 查询上一章id
        QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookChapterTable.COLUMN_BOOK_ID, bookId)
                .lt(DatabaseConstants.BookChapterTable.COLUMN_CHAPTER_NUM, chapterNum)
                .orderByDesc(DatabaseConstants.BookChapterTable.COLUMN_CHAPTER_NUM)
                .last(DatabaseConstants.SqlEnum.LIMIT_1.getSql());
        return RestResp.ok(
                Optional.ofNullable(bookChapterMapper.selectOne(queryWrapper))
                        .map(BookChapter::getId)
                        .orElse(null)
        );
    }

    @Override
    public RestResp<Long> getNextChapterId(Long chapterId) {
        BookChapterRespDto chapter = bookChapterCacheManager.getChapter(chapterId);
        Long bookId = chapter.getBookId();
        Integer chapterNum = chapter.getChapterNum();
        // 查询下一章id
        QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookChapterTable.COLUMN_BOOK_ID, bookId)
                .gt(DatabaseConstants.BookChapterTable.COLUMN_CHAPTER_NUM, chapterNum)
                .orderByAsc(DatabaseConstants.BookChapterTable.COLUMN_CHAPTER_NUM)
                .last(DatabaseConstants.SqlEnum.LIMIT_1.getSql());
        return RestResp.ok(
                Optional.ofNullable(bookChapterMapper.selectOne(queryWrapper))
                        .map(BookChapter::getId)
                        .orElse(null)
        );
    }

    @Override
    public RestResp<List<BookCategoryRespDto>> listCategory(Integer workDirection) {
        return RestResp.ok(bookCategoryCacheManager.listCategory(workDirection));
    }

    @Override
    public RestResp<List<BookEsRespDto>> listNextEsBooks(Long maxBookId) {
        QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.clear();
        queryWrapper.orderByAsc(DatabaseConstants.CommonColumnEnum.ID.getName())
                .gt(DatabaseConstants.CommonColumnEnum.ID.getName(), maxBookId)
                .gt(DatabaseConstants.BookTable.COLUMN_WORD_COUNT, 0)
                .last(DatabaseConstants.SqlEnum.LIMIT_30.getSql());
        return RestResp.ok(
                bookInfoMapper.selectList(queryWrapper).stream().map(
                        this::getBuild).toList());
    }

    private BookEsRespDto getBuild(BookInfo bookInfo) {
        return BookEsRespDto.builder()
                .id(bookInfo.getId())
                .categoryId(bookInfo.getCategoryId())
                .categoryName(bookInfo.getCategoryName())
                .bookDesc(bookInfo.getBookDesc())
                .bookName(bookInfo.getBookName())
                .authorId(bookInfo.getAuthorId())
                .authorName(bookInfo.getAuthorName())
                .bookStatus(bookInfo.getBookStatus())
                .commentCount(bookInfo.getCommentCount())
                .isVip(bookInfo.getIsVip())
                .score(bookInfo.getScore())
                .visitCount(bookInfo.getVisitCount())
                .wordCount(bookInfo.getWordCount())
                .workDirection(bookInfo.getWorkDirection())
                .lastChapterId(bookInfo.getLastChapterId())
                .lastChapterName(bookInfo.getLastChapterName())
                .lastChapterUpdateTime(
                        bookInfo.getLastChapterUpdateTime()
                                .toInstant(ZoneOffset.ofHours(8))
                                .toEpochMilli())
                .build();
    }

    @Override
    public RestResp<Void> publishBook(BookAddReqDto dto) {
        // 查询小说是否已经存在
        QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookTable.COLUMN_BOOK_NAME, dto.getBookName());
        if (bookInfoMapper.selectCount(queryWrapper) > 0) {
            // 该小说已经存在了
            return RestResp.fail(ErrorCodeEnum.AUTHOR_BOOK_NAME_EXIST);
        }
        // 设置小说作家信息
        BookInfo bookInfo = new BookInfo();
        bookInfo.setAuthorId(dto.getAuthorId());
        bookInfo.setAuthorName(dto.getPenName());
        // 设置小说信息
        bookInfo.setWorkDirection(dto.getWorkDirection());
        bookInfo.setCategoryId(dto.getCategoryId());
        bookInfo.setCategoryName(dto.getCategoryName());
        bookInfo.setBookName(dto.getBookName());
        bookInfo.setPicUrl(dto.getPicUrl());
        bookInfo.setBookDesc(dto.getBookDesc());
        bookInfo.setIsVip(dto.getIsVip());
        bookInfo.setScore(0);
        bookInfo.setCreateTime(LocalDateTime.now());
        bookInfoMapper.insert(bookInfo);
        return RestResp.ok();
    }

    @Override
    public RestResp<PageRespDto<BookInfoRespDto>> listAuthorBooks(BookPageReqDto dto) {
        IPage<BookInfo> page = new Page<>();
        page.setCurrent(dto.getPageNum());
        page.setSize(dto.getPageSize());
        QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookTable.AUTHOR_ID, dto.getAuthorId())
                .orderByDesc(DatabaseConstants.CommonColumnEnum.CREATE_TIME.getName());
        IPage<BookInfo> bookInfoPage = bookInfoMapper.selectPage(page, queryWrapper);
        return RestResp.ok(PageRespDto.of(dto.getPageNum(), dto.getPageSize(), bookInfoPage.getTotal(),
                bookInfoPage.getRecords().stream().map(
                        v -> BookInfoRespDto.builder()
                                .id(v.getId())
                                .bookName(v.getBookName())
                                .picUrl(v.getPicUrl())
                                .categoryName(v.getCategoryName())
                                .wordCount(v.getWordCount())
                                .visitCount(v.getVisitCount())
                                .updateTime(v.getUpdateTime())
                                .build()).toList()));
    }

    @Override
    public RestResp<Void> publishBookChapters(ChapterAddReqDto dto) {
        // 校验作品是否属于该作家
        BookInfo bookInfo = bookInfoMapper.selectById(dto.getBookId());
        if (!Objects.equals(bookInfo.getAuthorId(), dto.getAuthorId())) {
            return RestResp.fail(ErrorCodeEnum.USER_UN_AUTH);
        }
        // 保存相关信息到章节表
        // 查询并设置最新章节
        int chapterNum = 0;
        QueryWrapper<BookChapter> chapterQueryWrapper = new QueryWrapper<>();
        chapterQueryWrapper.eq(DatabaseConstants.BookChapterTable.COLUMN_BOOK_ID, dto.getBookId())
                .orderByDesc(DatabaseConstants.BookChapterTable.COLUMN_CHAPTER_NUM)
                .last(DatabaseConstants.SqlEnum.LIMIT_1.getSql());
        BookChapter bookChapter = bookChapterMapper.selectOne(chapterQueryWrapper);
        if (Objects.nonNull(bookChapter)) {
            chapterNum = bookChapter.getChapterNum() + 1;
        }

        // 保存章节信息
        BookChapter bookChapterNew = new BookChapter();
        bookChapterNew.setBookId(dto.getBookId());
        bookChapterNew.setChapterName(dto.getChapterName());
        bookChapterNew.setChapterNum(chapterNum);
        bookChapterNew.setWordCount(dto.getChapterContent().length());
        bookChapterNew.setIsVip(dto.getIsVip());
        bookChapterNew.setCreateTime(LocalDateTime.now());
        bookChapterNew.setUpdateTime(LocalDateTime.now());
        bookChapterMapper.insert(bookChapterNew);

        // 保存章节内容信息
        BookContent bookContent = new BookContent();
        bookContent.setChapterId(bookChapterNew.getId());
        bookContent.setContent(dto.getChapterContent());
        bookContent.setCreateTime(LocalDateTime.now());
        bookContentMapper.insert(bookContent);

        // 更新小说信息表中作品的章节信息
        BookInfo bookInfoNew = new BookInfo();
        bookInfoNew.setId(dto.getBookId());
        bookInfoNew.setLastChapterId(bookChapterNew.getId());
        bookInfoNew.setLastChapterName(bookChapterNew.getChapterName());
        bookInfoNew.setLastChapterUpdateTime(LocalDateTime.now());
        bookInfoNew.setWordCount(bookInfo.getWordCount() + bookChapterNew.getWordCount());
        bookInfoMapper.updateById(bookInfoNew);
        // 清除小说缓存
        bookInfoCacheManager.evictBookInfoCache(bookInfoNew.getId());
        // 调用mq异步通知es更新搜索文档
        rabbitTemplate.convertAndSend(AmqpConstants.BookChange.EXCHANGE_NAME,
                AmqpConstants.BookChange.INSERT_KEY, bookInfoNew.getId());
        return RestResp.ok();
    }

    @Override
    public RestResp<PageRespDto<BookChapterRespDto>> listBookChapters(ChapterPageReqDto dto) {
        IPage<BookChapter> page = new Page<>();
        page.setSize(dto.getPageSize());
        page.setCurrent(dto.getPageNum());
        QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookChapterTable.COLUMN_BOOK_ID, dto.getBookId())
                .orderByDesc(DatabaseConstants.BookChapterTable.COLUMN_CHAPTER_NUM);
        IPage<BookChapter> bookChapterPage = bookChapterMapper.selectPage(page, queryWrapper);
        return RestResp.ok(PageRespDto.of(dto.getPageNum(), dto.getPageSize(), bookChapterPage.getTotal(),
                bookChapterPage.getRecords().stream().map(
                        v -> BookChapterRespDto.builder()
                                .id(v.getId())
                                .chapterName(v.getChapterName())
                                .chapterUpdateTime(v.getUpdateTime())
                                .isVip(v.getIsVip())
                                .chapterUpdateTime(v.getUpdateTime())
                                .build()).toList()));
    }

    @Override
    public RestResp<BookChapterContentRespDto> getChapterContent(ChapterContentReqDto dto) {
        // 检验作品是否属于该作者
        BookChapter bookChapter = bookChapterMapper.selectById(dto.getChapterId());
        BookInfo bookInfo = bookInfoMapper.selectById(bookChapter.getBookId());
        if (!Objects.equals(bookInfo.getAuthorId(), dto.getAuthorId())) {
            throw new BusinessException(ErrorCodeEnum.USER_UN_AUTH);
        }
        QueryWrapper<BookContent> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookContentTable.COLUMN_CHAPTER_ID, dto.getChapterId())
                .last(DatabaseConstants.SqlEnum.LIMIT_1.getSql());
        BookContent bookContent = bookContentMapper.selectOne(queryWrapper);
        // 获取章节信息
        return RestResp.ok(
                BookChapterContentRespDto.builder()
                        .id(bookChapter.getId())
                        .bookId(bookChapter.getBookId())
                        .authorId(bookInfo.getAuthorId())
                        .chapterName(bookChapter.getChapterName())
                        .chapterContent(bookContent.getContent())
                        .isVip(bookChapter.getIsVip())
                        .build()
        );
    }

    @Override
    public RestResp<Void> updateChapter(ChapterAddReqDto dto) {
        BookChapter bookChapter = bookChapterMapper.selectById(dto.getId());
        Integer wordCount = bookChapter.getWordCount();
        // 更新小说章节表
        bookChapter.setChapterName(dto.getChapterName());
        bookChapter.setIsVip(dto.getIsVip());
        bookChapter.setUpdateTime(LocalDateTime.now());
        bookChapter.setWordCount(dto.getChapterContent().length());
        bookChapterMapper.updateById(bookChapter);
        // 更新小说内容表
        BookContent bookContent = new BookContent();
        bookContent.setChapterId(dto.getId());
        bookContent.setContent(dto.getChapterContent());
        bookContent.setUpdateTime(LocalDateTime.now());
        QueryWrapper<BookContent> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookContentTable.COLUMN_CHAPTER_ID, dto.getId())
                        .last(DatabaseConstants.SqlEnum.LIMIT_1.getSql());
        bookContentMapper.update(bookContent, queryWrapper);
        // 更新书籍表
        BookInfo bookInfo = bookInfoMapper.selectById(dto.getBookId());
        bookInfo.setWordCount(bookInfo.getWordCount() + dto.getChapterContent().length() - wordCount);
        // 判断当前更新是否为最新一章
        if (Objects.equals(bookInfo.getLastChapterId(), dto.getId())) {
            bookInfo.setLastChapterName(dto.getChapterName());
            bookInfo.setLastChapterUpdateTime(LocalDateTime.now());
            bookInfo.setUpdateTime(LocalDateTime.now());
        }
        bookInfoMapper.updateById(bookInfo);
        bookInfoCacheManager.evictBookInfoCache(dto.getBookId());
        bookChapterCacheManager.evictChapterCache(dto.getId());
        bookContentCacheManager.evictBookContentCache(dto.getId());
        // 调用mq异步通知es更新搜索文档
        rabbitTemplate.convertAndSend(AmqpConstants.BookChange.EXCHANGE_NAME,
                AmqpConstants.BookChange.UPDATE_KEY, bookInfo.getId());
        return RestResp.ok();
    }

    @Override
    public RestResp<Void> deleteChapter(ChapterContentReqDto dto) {
        // 判断是否属于当前作者
        BookChapter bookChapter = bookChapterMapper.selectById(dto.getChapterId());
        BookInfo bookInfo = bookInfoMapper.selectById(bookChapter.getBookId());
        if (!Objects.equals(bookInfo.getAuthorId(), dto.getAuthorId())) {
            throw new BusinessException(ErrorCodeEnum.USER_UN_AUTH);
        }
        Integer wordCount = bookChapter.getWordCount();
        // 删除章节信息
        bookChapterMapper.deleteById(dto.getChapterId());
        bookChapterCacheManager.evictChapterCache(dto.getChapterId());
        QueryWrapper<BookContent> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.BookContentTable.COLUMN_CHAPTER_ID, dto.getChapterId())
                .last(DatabaseConstants.SqlEnum.LIMIT_1.getSql());
        bookContentMapper.delete(queryWrapper);
        bookContentCacheManager.evictBookContentCache(dto.getChapterId());
        // 更新书籍表
        bookInfo.setWordCount(bookInfo.getWordCount() - wordCount);
        if (Objects.equals(dto.getChapterId(), bookInfo.getLastChapterId())) {
            QueryWrapper<BookChapter> chapterQueryWrapper = new QueryWrapper<>();
            chapterQueryWrapper.eq(DatabaseConstants.BookChapterTable.COLUMN_BOOK_ID, bookInfo.getId())
                    .orderByDesc(DatabaseConstants.BookChapterTable.COLUMN_CHAPTER_NUM)
                    .last(DatabaseConstants.SqlEnum.LIMIT_1.getSql());
            BookChapter bookChapterNew = bookChapterMapper.selectOne(chapterQueryWrapper);
            if (Objects.nonNull(bookChapterNew)) {
                bookInfo.setLastChapterId(bookChapterNew.getId());
                bookInfo.setLastChapterName(bookChapterNew.getChapterName());
                bookInfo.setUpdateTime(LocalDateTime.now());
                bookInfoMapper.updateById(bookInfo);
                rabbitTemplate.convertAndSend(AmqpConstants.BookChange.EXCHANGE_NAME,
                        AmqpConstants.BookChange.UPDATE_KEY, bookInfo.getId());
            } else {
                bookInfo.setUpdateTime(LocalDateTime.now());
                bookInfoMapper.updateById(bookInfo);
                rabbitTemplate.convertAndSend(AmqpConstants.BookChange.EXCHANGE_NAME,
                        AmqpConstants.BookChange.DELETE_KEY, bookInfo.getId());
            }
        }
        return RestResp.ok();
    }

    @Override
    public RestResp<BookEsRespDto> selectEsBookById(Long bookId) {
        QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DatabaseConstants.CommonColumnEnum.ID.getName(), bookId)
                .gt(DatabaseConstants.BookTable.COLUMN_WORD_COUNT, 0);
        BookInfo bookInfo = bookInfoMapper.selectOne(queryWrapper);
        if (Objects.isNull(bookInfo)) {
            return RestResp.ok(BookEsRespDto.builder().build());
        }
        return RestResp.ok(
                getBuild(bookInfo)
        );
    }
}
